/*

 */
/* 
 *  File:   main.cpp
 *  Author: 
 *  
 *  Created on March 28, 2015, 12:01 AM
 */
 
#include "LocalSdk.h"
#include "inifiles.h"
#include "xmcamera.h"
#include "fossa.h"
#include "calllater.h"

#include <signal.h>

#include "stdio.h"
#include <string.h>
#include <stdlib.h>
#include "signal.h"
#include "netdb.h"
#include <arpa/inet.h>
#include <sys/wait.h>
#include <errno.h>
#include <time.h>

#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/if_ether.h>
#include <net/if.h>
#include <linux/sockios.h>



#define kVersionString "0.1"
#define kBuildString "15.0813"

#define PING_INTER_SEC 5
#define MAX_PING_NUM 1

 #define PING_SUCC NSF_USER_1 
 #define PING_WAIT NSF_USER_2 
 #define PING_FAIL NSF_USER_3 


 //using namespace std;

string sCmsFullAddr,sSMSAddr;
int iDevicePort,iSMSPort;
string sDeviceAddr, sDeviceUserName, sDevicePassword, sDeviceSerial;
int iStreamFlag, iAudioEnable, iAACEncode, iMediaBufferSize, iAudio_sample_rate;



static int s_exit_flag = 0;

static delay_queue_t *delay_queue0;

xmcamera *camera;

int get_mac(char* mac, const char* ethDeviceName);
static void dev_keep_alive(void * client_data);
int parsercmd(char const *cmd);
static void ev_handler(struct ns_connection *nc, int ev, void *ev_data);


static int config_param(void)
{
    //Central Management Server Configuration:
    string sCmsProto = IniReadString("server", "cms_proto", "tcp", "xmcamera.ini"); 
    string sCmsIp = IniReadString("server", "cms_addr", "127.0.0.1", "xmcamera.ini"); 
    string sCmsPort = IniReadString("server", "cms_port", "80", "xmcamera.ini");//For string concatation use only.
    int iCmsPort = IniReadInteger("server", "cms_port", 80, "xmcamera.ini");
    sCmsFullAddr = sCmsProto + "://" + sCmsIp + ":" + sCmsPort;
   
   //Stream Main Server Configuration:
       //SMSµØÖ·
    sSMSAddr = IniReadString("server", "sms_addr", "192.168.1.168", "/mnt/custom/xmcamera.ini");
    //SMS¶Ë¿Ú
    iSMSPort = IniReadInteger("server", "sms_port", 554, "/mnt/custom/xmcamera.ini");

    //Éè±¸µØÖ·
    sDeviceAddr = IniReadString("device", "address", "127.0.0.1", "/mnt/custom/xmcamera.ini");
    //Éè±¸¶Ë¿Ú
    iDevicePort = IniReadInteger("device", "port", 80, "/mnt/custom/xmcamera.ini");
  
    //Éè±¸ÓÃ»§Ãû
    sDeviceUserName = IniReadString("device", "username", "admin", "/mnt/custom/xmcamera.ini");
    //Éè±¸ÃÜÂë
    sDevicePassword = IniReadString("device", "password", "admin", "/mnt/custom/xmcamera.ini");
    //Éè±¸ÂëÁ÷Êä³ö£¬1£ºÖ÷ÂëÁ÷ 0£º´ÎÂëÁ÷
    iStreamFlag = IniReadInteger("device", "stream_flag", 1, "/mnt/custom/xmcamera.ini");
    //ÊÇ·ñÊä³öÒôÆµ£¬1£ºÊä³ö 0£º²»Êä³ö
    iAudioEnable = IniReadInteger("device", "audio_enable", 1, "/mnt/custom/xmcamera.ini");
    //ÒôÆµÊÇ·ñAAC±àÂë£¬1£º±àÂë 0£º²»±àÂë
    iAACEncode = IniReadInteger("device", "aac_encode", 1, "/mnt/custom/xmcamera.ini");
     //Audio ²ÉÑùÂÊ 
    iAudio_sample_rate=IniReadInteger("device","audio_sample_rate",8000,"/mnt/custom/xmcamera.ini");
    //Éè±¸¶Ë»º³å´óÐ¡£¬0~500£¬0±íÊ¾²»ÏÞÖÆ
    iMediaBufferSize = IniReadInteger("device", "media_buf_size", 100, "/mnt/custom/xmcamera.ini");
 
   //Éè±¸Íø¿¨Ãû³Æ 
    string sDeviceNetInterface = IniReadString("device", "net_interface", "eth0", "/mnt/custom/xmcamera.ini");
    char mac[30];
    if(get_mac(mac,sDeviceNetInterface.c_str())!=0)
        {
            printf("Wring:Could not obtain MAC address on interface-%s",sDeviceNetInterface.c_str());
            return -1;
        }
     sDeviceSerial = string(mac)+string(".sdp");
  //   printf("%s\n", sDeviceSerial.c_str());
    return 0;
}

int runStreamPush()
{
    
    printf("device[%s]/v%s (Build/%s) is now running\n", sDeviceSerial.c_str(), kVersionString, kBuildString);
    camera = new xmcamera();
    camera->initialize();
    camera->start_stream_push(sSMSAddr.c_str(), iSMSPort, sDeviceSerial.c_str(), "", "", iMediaBufferSize,EASY_SDK_VIDEO_CODEC_H264,EASY_SDK_AUDIO_CODEC_G711A,(Easy_U32)iAudio_sample_rate);

    // while (true)
    // {
    // #ifndef _WIN32
    //         sleep(1);
    // #else
    //         Sleep(1000);
    // #endif
    //     }
    return 0;
}



int runServer()
{
 
  static struct ns_connection *nc;
   static struct ns_mgr mgr;

  ns_mgr_init(&mgr, NULL);

  nc = ns_connect(&mgr, sCmsFullAddr.c_str(), ev_handler);
  if(nc==NULL)
  {
  	printf("Socket open failed\n");
  	return -1;
  }
  printf("Server at %s started\n",sCmsFullAddr.c_str());
  while (s_exit_flag == 0) {
    ns_mgr_poll(&mgr, 1000);
    time_synchronize(delay_queue0);
  }
  s_exit_flag = 0;
  ns_mgr_free(&mgr);

  return 1;
}
static void initialize(void)
{
	 delay_queue0=delay_queue_init();

}
static void uninitialize(void)
{
   	delay_queue_destory(delay_queue0);
}


int main(int argc, char** argv)
{
    if(config_param())
    	printf("Parameter wrong!\n");
    initialize();
    
     runStreamPush();

    int ret = runServer();
    printf("closed\n");
   while(1)
  {
  	if(ret==-1)
  	{
  		printf("No network connection\n");
  		sleep(5);
  	}
   	uninitialize();
 	 initialize();
   ret = runServer();
   }

    return 0;
}
static void ev_handler(struct ns_connection *nc, int ev, void *ev_data) {
//  struct http_message *hm = (struct http_message *) ev_data;
  struct mbuf *io = &nc->recv_mbuf;
  int connect_status;
  switch (ev) {
  	case NS_POLL:
  		if(nc->flags&PING_FAIL)
  		nc->flags |= NSF_CLOSE_IMMEDIATELY;
  	break;

  	case NS_SEND:
  		printf("sent ...\n");
  		break;

	case NS_CONNECT:	
		connect_status= * (int *) ev_data;
		if(connect_status==0){
			
			printf("Connected to %s\n",sCmsFullAddr.c_str());
			char reportAddr[128];
			sprintf(reportAddr,"1 %s %ld\n",sDeviceSerial.c_str(),time(NULL));
			ns_send(nc, reportAddr,strlen(reportAddr));
			//dev_keep_alive(nc);

			nc->flags |=PING_SUCC;
			nc->flags &=~PING_WAIT;		

			nc->user_data = (int *)malloc(sizeof(int));
			int* ping_num = (int *) nc->user_data;
			*ping_num = 0;

			call_later(PING_INTER_SEC,dev_keep_alive,nc,delay_queue0);
			s_exit_flag=0;
		}
		else
		{
			printf("Trying to connect to %s failed. \n",sCmsFullAddr.c_str());
			s_exit_flag = 1;
		}
	break;
    case NS_RECV:
      {
      	printf("Now is %ld, Receive:%s \n",time(NULL),io->buf);
        char resp[128];
        char time_stamp[32];
        int cmdNo=0;
        int ret=sscanf(io->buf,"%*[^:]:%d %s %s",&cmdNo,resp,time_stamp);

        if(cmdNo==0 && (strcmp(resp,"ping")==0))
        {
        	printf("receive pong\n");
        	nc->flags |= PING_SUCC;
      		nc->flags &=~PING_WAIT;
     	}
      //  if(ret>0)
      // {
      // 	char echo[64]="\0";
      //  	sprintf(echo,"%d %s resp\n", cmdNo,resp);
      //    printf(" Sending %s\n",echo );
      // 	 ns_send(nc,echo,strlen(echo));
      //	 ns_write_to_socket(nc);
      //}
      mbuf_remove(io, io->len);
      s_exit_flag=0;
      
      }
	break;

    case NS_CLOSE:
    	printf("Closed\n");
        if(nc->user_data != NULL)
  		  free(nc->user_data);
    	s_exit_flag=1;
    	break;

	 default:
		break;
  }
}
static void dev_keep_alive(void * client_data)
{
	struct ns_connection *nc = (struct ns_connection *)client_data;
	 char ping_message_head[] = "0 ping";
    char ping_message[64];
    sprintf(ping_message,"%s %ld",ping_message_head,time(NULL));
    int * ping_num = (int *)nc->user_data;

	if (delay_queue0==NULL)
		delay_queue0=delay_queue_init();

	if (nc==NULL)
	{
		printf("-------------- No connection---------------\n");
		return;
	}

	if(nc->flags&PING_SUCC)
	{
		nc->flags |=PING_WAIT;
		nc->flags &=~PING_SUCC;
		*ping_num = 1;
		printf("ping sending...\n");
		ns_send(nc,ping_message,strlen(ping_message));
		
	}
	else
		if(nc->flags&PING_WAIT)
      {
      	printf("****Last ping failed*****\n");
			if(*ping_num < MAX_PING_NUM)
			{
				(*ping_num)++;
				printf("ping again...\n");
				ns_send(nc,ping_message,strlen(ping_message));
			}
			else
				nc->flags |= PING_FAIL;
	  }
	call_later(PING_INTER_SEC,dev_keep_alive,client_data,delay_queue0);//Repeat calling itself, it is posssible to call other function
}

int parsercmd(char const *cmd)
{
	//"commandNumber argv1 agv2 agv3"
	//push a stream, commandNumber=1; "1 streamname1 rtsp://192.168.1.168:554/live.sdp username passwd 218.76.2.32 554 [username] [passwd]"
	//close a stream, commandNumber=2; "2 streamname1"
	//
	printf(cmd);
	int ret;
	int cmdopitional;
    char streamname[100];
    char rtspsource[1024];
    char usernamesrc[100];
    char passwordsrc[100];
    char hostdest[100];
    int portdest;
//    char usernamedest[100];
//    char passwddest[100];
	ret=sscanf(cmd,"%d%*s", &cmdopitional);
	switch (cmdopitional)
	{
		case 1:
		{
			ret=sscanf(cmd,"%*s %s %s %s %s %s %d %*s", streamname,rtspsource,usernamesrc,passwordsrc,hostdest,&portdest);
/*			if (ret>5)
			{
				streamInjector *streamInjector1;
				streamInjector1=new streamInjector(rtspsource, 1, streamname, usernamesrc,passwordsrc,hostdest,portdest);
				Item *pusherItem;
				string sstreamname(streamname);
				pusherItem=new Item(sstreamname,streamInjector1);
				pushertable->insertItem(pusherItem);
				streamInjector1->start_push();
			}*/
			break;
		}
		case 2:
		{
			ret=sscanf(cmd,"%*s %s", streamname);
			string sstreamname(streamname);
			break;
		}
		default:
			break;
	}
	return 1;
}

static int exit_flag = 0;

static void TerminateHandler(int sigNumber)
{
    printf("xmcamera terminated[%d]\n", sigNumber);
    exit_flag = sigNumber;
    exit(0);
}

void LogCallback(const char* msg, void* pClient)
{
    printf("\n%s\n", msg);
}
int get_mac(char* mac, const char* ethDeviceName)
{
    struct ifreq tmp;
    int sock_mac;
    char mac_addr[30];
    sock_mac = socket(AF_INET, SOCK_STREAM, 0);
    if( sock_mac == -1){
        perror("create socket fail\n");
        return -1;
    }
    memset(&tmp,0,sizeof(tmp));
    strncpy(tmp.ifr_name,ethDeviceName,sizeof(tmp.ifr_name)-1 );
    if( (ioctl( sock_mac, SIOCGIFHWADDR, &tmp)) < 0 ){
        printf("mac ioctl error\n");
        return -1;
    }
    sprintf(mac_addr, "%02x%02x%02x%02x%02x%02x",
            (unsigned char)tmp.ifr_hwaddr.sa_data[0],
            (unsigned char)tmp.ifr_hwaddr.sa_data[1],
            (unsigned char)tmp.ifr_hwaddr.sa_data[2],
            (unsigned char)tmp.ifr_hwaddr.sa_data[3],
            (unsigned char)tmp.ifr_hwaddr.sa_data[4],
            (unsigned char)tmp.ifr_hwaddr.sa_data[5]
            );
  //  printf("local mac:%s\n", mac_addr);
    close(sock_mac);
    memcpy(mac,mac_addr,strlen(mac_addr)+1);
    return 0;
}
